﻿using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using Cloak.Autofac;
using Cloak.Globalization;
using Cloak.Mvp.Autofac.ViewParameters;

namespace Cloak.Mvp.Autofac
{
	/// <summary>
	/// Configures view/presenter mappings and units of work for the MVP system
	/// </summary>
	public class MvpModule : BuilderModule
	{
		/// <summary>
		/// Initializes a module with the specified presenter index. Registers presenter types referenced by views in
		/// the specified assemblies.
		/// </summary>
		/// <param name="viewPresenterIndex">The mapping between views and presenters</param>
		/// <param name="viewAssemblies">
		/// The assemblies containing views whose presenter types will be automatically registered
		/// </param>
		public MvpModule(IViewPresenterIndex viewPresenterIndex, IEnumerable<Assembly> viewAssemblies)
		{
			Contract.Requires(viewPresenterIndex != null);
			Contract.Requires(viewAssemblies != null);

			RegisterInstance(viewPresenterIndex).SingleInstance().ExternallyOwned();

			RegisterInstance(new CompositeViewParameterSpecification(
				new ViewParameterFirstSpecification(),
				new ViewParameterAttributedSpecification()))
			.As<IViewParameterSpecification>()
			.SingleInstance();

			RegisterType<PresenterContext>().As<IPresenterContext>().InstancePerLifetimeScope();

			RegisterType<MvpContext>().As<IMvpContext>().InstancePerLifetimeScope();

			this.RegisterPresenters(viewPresenterIndex, viewAssemblies);
		}

		/// <summary>
		/// Initializes a module with the specified presenter index. Registers presenter types referenced by views in
		/// the specified assemblies.
		/// </summary>
		/// <param name="viewPresenterIndex">The mapping between views and presenters</param>
		/// <param name="viewAssemblies">
		/// The assemblies containing views whose presenter types will be automatically registered
		/// </param>
		public MvpModule(IViewPresenterIndex viewPresenterIndex, params Assembly[] viewAssemblies)
			: this(viewPresenterIndex, viewAssemblies as IEnumerable<Assembly>)
		{}

		/// <summary>
		/// Initializes a module with the specified presenter index
		/// </summary>
		/// <param name="viewPresenterIndex">The mapping between views and presenters</param>
		public MvpModule(IViewPresenterIndex viewPresenterIndex)
			: this(viewPresenterIndex, Enumerable.Empty<Assembly>())
		{}

		/// <summary>
		/// Initializes a module and registers presenter types referenced by views in the specified assemblies
		/// </summary>
		/// <param name="viewAssemblies">
		/// The assemblies containing views whose presenter types will be automatically registered
		/// </param>
		public MvpModule(IEnumerable<Assembly> viewAssemblies)
			: this(new CachingViewPresenterIndex(new AttributedViewPresenterIndex()), viewAssemblies)
		{}

		/// <summary>
		/// Initializes a module and registers presenter types referenced by views in the specified assemblies
		/// </summary>
		/// <param name="viewAssemblies">
		/// The assemblies containing views whose presenter types will be automatically registered
		/// </param>
		public MvpModule(params Assembly[] viewAssemblies)
			: this(viewAssemblies as IEnumerable<Assembly>)
		{}

		/// <summary>
		/// Initializes a module with an attributed view/presenter index
		/// </summary>
		public MvpModule()
			: this(Enumerable.Empty<Assembly>())
		{}
	}
}